/***************************************************************************
 *   This file is part of KLabeler                                         *
 *   Copyright (C) 2010 by Luca Bellonda                                   *
 *   lbellonda _at_ gmail.com                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "config-klabeler.h"
#include <QtCore/QSharedDataPointer>
#include <QtCore/QList>
#include <QStringList>
#include <QSet>

#include <Nepomuk/ResourceManager>
#include <Nepomuk/Resource>
#include <Nepomuk/Variant>

#include <Nepomuk/Tag>

#include <Soprano/Version>
#include <Soprano/Model>
#include <Soprano/QueryResultIterator>
#include <Soprano/Node>
#include <Soprano/Statement>
#include <Soprano/LiteralValue>
#include <Soprano/StatementIterator>
#include <Soprano/Vocabulary/NAO>
#include <Soprano/Vocabulary/Xesam>

#include "nepomukManager.h"
#define NIEURL  "http://www.semanticdesktop.org/ontologies/2007/01/19/nie#url"


#define SOURCE_CLASS "configurationManager"


NepomukManager::NepomukManager()
{
    isReady = false;
    setupLog();
}

NepomukManager::~NepomukManager()
{
    logger.debug(&logParam, "end");
}

bool NepomukManager::init()
{
#ifndef USE_NEPOMUK
    isReady = true ;
    return true;
#endif
    if (!isReady) {
        logger.debug(&logParam, "init");
        if (0 != Nepomuk::ResourceManager::instance()->init()) {
            return false;
        }
        isReady = true ;
    }
    return true;
}

bool NepomukManager::addTagListToResource(const QString& resource, const QStringList &tags)
{
    logger.debug(&logParam, "addTagListToResource enter");
    if (!init()) {
        return false;
    }
    bool allOk = true ;
    logger.debug(&logParam, "addTagListToResource begin work");
    foreach(QString tag, tags) {
        if (!addTagToResource(resource, tag)) {
            allOk = false;
            break;
        }
    }
    if (logger.isLoggable(TLogger::DEBUG)) {
        logger.debug(&logParam, QString("addTagListToResource end work res=%1").arg(allOk));
    }
    return allOk ;
}

bool NepomukManager::addTagToResource(const QString& resource, const QString &tagTitle)
{
    bool isOk = true ;
    logger.debug(&logParam, "addTagToResource enter");

    if (!init()) {
        return false;
    }
    logger.debug(&logParam, "addTagToResource begin work");

    //Nepomuk::Resource nepomukTag(tag, Soprano::Vocabulary::NAO::Tag());
    Nepomuk::Tag tag(tagTitle);
    tag.setLabel(tagTitle);
    tag.setProperty(Soprano::Vocabulary::NAO::prefLabel(), tagTitle);

    Nepomuk::Resource aFile(resource, Soprano::Vocabulary::Xesam::File());
    aFile.addTag(tag);
    //aFile.setProperty(Soprano::Vocabulary::NAO::hasTag(), nepomukTag);

    if (logger.isLoggable(TLogger::DEBUG)) {
        logger.debug(&logParam, QString("addTagToResource end work res=%1").arg(isOk));
    }

    /* alternative method
    Nepomuk::Tag tag( tag );

    Nepomuk::File aFile( resource );
    aFile.addTag( tag );
    */
    return isOk ;
}


bool NepomukManager::removeTagFromResource(const QString& resource, const QString &tag)
{
    bool isOk = true;
    logger.debug(&logParam, "removeTagFromResource enter");
#ifndef USE_NEPOMUK
    return true;
#endif
    if (!init()) {
        return false;
    }
    logger.debug(&logParam, "removeTagFromResource begin work");

    //Nepomuk::Resource nepomukTag(tag, Soprano::Vocabulary::NAO::Tag());
    Nepomuk::Tag nepomukTag(tag);

    Nepomuk::Resource aFile(resource, Soprano::Vocabulary::Xesam::File());
    //aFile.removeProperty(nepomukTag.tagUri());
    aFile.removeProperty(Soprano::Vocabulary::NAO::hasTag(), nepomukTag.resourceUri());

    if (logger.isLoggable(TLogger::DEBUG)) {
        logger.debug(&logParam, QString("removeTagFromResource end work res=%1").arg(isOk));
    }

    return isOk ;
}
/*

bool NepomukManager::clearResource(const QString& resource)
{
    bool isOk = true;
    logger.debug(&logParam, "removeTagFromResource enter");
#ifndef USE_NEPOMUK
    return true;
#endif
    if (!init()) {
        return false;
    }
    logger.debug(&logParam, "removeTagFromResource begin work");

    Nepomuk::Resource aFile(resource, Soprano::Vocabulary::Xesam::File());
    aFile.removeProperty(Soprano::Vocabulary::NAO::hasTag(), nepomukTag);
    aFile.removeProperty(Soprano::Vocabulary::NAO::hasTag(), nepomukTag);

    if (logger.isLoggable(TLogger::DEBUG)) {
        logger.debug(&logParam, QString("removeTagFromResource end work res=%1").arg(isOk));
    }

    return isOk ;
}
*/

void NepomukManager::setupLog()
{
    logParam.source = SOURCE_CLASS;
}

QStringList NepomukManager::getAllTags()
{
    logger.debug(&logParam, "NepomukManager::getAllTags enter");
    QStringList result;
#ifndef USE_NEPOMUK
    result.append("Books - MOCKUP");
    result.append("Java - MOCKUP");
    result.append("Programming- MOCKUP");
    result.append("Auto - MOCKUP");
    return result;
#endif

    QString query = QString(
                        "PREFIX nao: <%1> "
                        " select distinct ?l where { "
                        " ?r %2 ?t ."
                        " ?t %3 ?l ."
                        " } ")
                    .arg(Soprano::Vocabulary::NAO::naoNamespace().toString())   //1
                    .arg(Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::hasTag()))   //2
                    .arg(Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::prefLabel()))   //3
                    ;
    logger.debug(&logParam, QString("QUERY: %1\n\n").arg(query));
    Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery(query,
                                      Soprano::Query::QueryLanguageSparql);
    while (it.next()) {
        QString tag = it.binding("l").toString() ;
        logger.debug(&logParam, QString("found tag : %1").arg(tag));
        result.append(tag);
    }
    logger.debug(&logParam, QString("end getAllTags, found tags : %1").arg(result.count()));
    return result;
}

#include <Nepomuk/Tag> //TODO
#include <Soprano/Vocabulary/RDF>
#include <Soprano/Vocabulary/RDFS>

QStringList NepomukManager::getTagsOfResource(const QString &resourcePath)
{
    logger.debug(&logParam, "NepomukManager::getTagsOfResource enter");
    QStringList result;
#ifndef USE_NEPOMUK
    result.append("Uno - MOCKUP");
    result.append("Two - MOCKUP");
    return result ;
#endif
    QString query = QString(
                        "PREFIX nao: <%1> "
                        " select distinct ?l where { "
                        " ?r %2 ?t ."
                        " ?t %3 ?l ."
                        " ?r <%4> <%5> ."
                        " } ")
                    .arg(Soprano::Vocabulary::NAO::naoNamespace().toString())   //1
                    .arg(Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::hasTag()))   //2
                    .arg(Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::prefLabel()))   //3
                    .arg(NIEURL)   //4
                    .arg(resourcePath) //5
                    ;
    logger.debug(&logParam, QString("QUERY: %1\n\n").arg(query));
    Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery(query,
                                      Soprano::Query::QueryLanguageSparql);
    while (it.next()) {
        QString tag = it.binding("l").toString() ;
        logger.debug(&logParam, QString("found tag : %1").arg(tag));
        result.append(tag);
    }
    logger.debug(&logParam, QString("end getTagsOfResource, found tags : %1").arg(result.count()));
    return result;

    /*    logger.debug(&logParam, "NepomukManager::getTagsOfResource enter");
        QStringList result;
    #ifndef USE_NEPOMUK
        result.append("Uno - MOCKUP");
        result.append("Two - MOCKUP");
        return result ;
    #endif
        Nepomuk::Resource theFile( resourcePath );
        QList<Nepomuk::Tag> tags = theFile.tags();
        foreach( Nepomuk::Tag tag, tags ) {
            QString label = tag.property(Soprano::Vocabulary::RDFS::label()).toString();
            logger.debug(&logParam, QString("found tag : %1").arg(label));
            result.append(label);
        }

        logger.debug(&logParam, QString("end getTagsOfResource, found tags : %1").arg(result.count()));
        return result;
        */
    /*
    // get the "max" first tags with the most resources
     QString query = QString::fromLatin1("select ?r count(distinct ?f) as ?c where { "
                                         "?r a %1 . "
                                         "?f %2 ?r . "
                                         "} ORDER BY DESC(?c) LIMIT %3")
                     .arg( Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::Tag()),
                           Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::hasTag()))
                     .arg( max );
     QList<Nepomuk::Tag> tags;


     Soprano::QueryResultIterator it = ResourceManager::instance()->mainModel()->executeQuery( query, Soprano::Query::QueryLanguageSparql );
     while( it.next()
         logger.debug(&logParam, "NepomukManager::getTagsOfResource enter");
         QStringList result;
     #ifndef USE_NEPOMUK
         result.append("Uno - MOCKUP");
         result.append("Two - MOCKUP");
         return result ;
     #endif
         QString query = QString(
                             "PREFIX nao: <%1> "
                             " select distinct ?l where { "
                             " ?r %2 ?t ."
                             " ?t %3 ?l ."
                             " ?r <%4> <%5> ."
                             " } ")
                         .arg(Soprano::Vocabulary::NAO::naoNamespace().toString())   //1
                         .arg(Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::hasTag()))   //2
                         .arg(Soprano::Node::resourceToN3(Soprano::Vocabulary::NAO::prefLabel()))   //3
                         .arg(NIEURL)   //4
                         .arg(resourcePath) //5
                         ;
         logger.debug(&logParam, QString("QUERY: %1\n\n").arg(query));
         Soprano::QueryResultIterator it = Nepomuk::ResourceManager::instance()->mainModel()->executeQuery(query,
                                           Soprano::Query::QueryLanguageSparql);
         while (it.next()) {
             QString tag = it.binding("l").toString() ;
             logger.debug(&logParam, QString("found tag : %1").arg(tag));
             result.append(tag);
         }
         logger.debug(&logParam, QString("end getTagsOfResource, found tags : %1").arg(result.count()));
         return result;
         */
}

//TODO VERIFICARE
bool NepomukManager::saveTags(const QString &resource, QStringList &confirmedTags, QStringList &currentlyAssignedTags)
{
    // find tags to delete
    QSet<QString> tagSet;
    foreach(QString value, confirmedTags) {
        tagSet.insert(value);
    }
    QStringList tagsToDelete;
    // set all others
    foreach(QString oldTag, currentlyAssignedTags) {
        if (!tagSet.contains(oldTag)) {
            tagsToDelete.append(oldTag);
        }
    }
    // exec operations
    foreach(QString badTag, tagsToDelete) {
        if (!removeTagFromResource(resource, badTag)) {
            logger.error(&logParam, "NepomukManager::saveTags return false 1");
            return false;
        }
    }
    if (!addTagListToResource(resource, confirmedTags)) {
        logger.error(&logParam, "NepomukManager::saveTags return false 2");
        return false;
    }
    logger.debug(&logParam, "NepomukManager::saveTags return true");
    return true;
}


